/*
 * Angry Monsters, Windows Mobile 7 XNA Game FW demo
 * Tero Paananen, tepaanan@gmail.com
 * 2011 Finland
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input.Touch;


// http://box2dxna.codeplex.com
using Box2D.XNA;

namespace WP7Box2d
{
    /* ***********************************************************************
     * LevelEditorItem
     */
    public class LevelEditorItem
    {
        public enum EditorItemType
        {
            EBox1 = 0,
            EBox2p = 1,
            EBox2l = 2,
            EBox3p = 3,
            EBox3l = 4,
            EBox4p = 5,
            EBox4l = 6,
            EEnemy1 = 7,
            EEnemy2 = 8,
            EEnemy3 = 9
        }
        public bool m_placeholder; // If true do not create Box2D body from that item
        public EditorItemType m_type;
        public Rectangle m_rectangle;
        public Texture2D m_texture;

        public LevelEditorItem(bool placeholder, EditorItemType type, Rectangle rectangle, Texture2D texture)
        {
            m_placeholder = placeholder;
            m_type = type;
            m_rectangle = rectangle;
            m_texture = texture;
        }
    }
    
    /* ***********************************************************************
     * Level Handler
     */
    class LevelHandler : ButtonListenerIF
    {
        protected BoxHandler m_boxHandler = null;

        // Event delegate
        public delegate void GameStateChangedEventHandler(GameEngine.GameState newState);
        // Event to send
        public event GameStateChangedEventHandler GameStateChanged;

        protected int m_level;

        protected LevelEditorItem m_activeLevelItem = null;
        protected int m_xCap;
        protected int m_yCap;

        protected Button m_playBtn = null;
        protected Button m_saveBtn = null;
        protected Button m_cancelBtn = null;

        protected Button m_leftBtn = null;
        protected Button m_rightBtn = null;

        protected float m_cameraOffset = 0.0f;

        protected List<LevelEditorItem> m_levelData = new List<LevelEditorItem>();

        protected Rectangle m_prevPos;

        protected ContentManager m_cm;

        public LevelStorage m_levelStorage = null;

        public LevelHandler()
        {
        }

        public virtual void CreateLevelStorage(bool createDefaultLevels)
        {
            m_levelStorage = new LevelStorage(createDefaultLevels);
        }

        public LevelHandler(ContentManager cm, ref BoxHandler box)
        {
            m_cm = cm;
            m_boxHandler = box;

        }

        public virtual void LoadContent()
        {
            LoadContent(m_cm);
        }


        protected virtual void LoadContent(ContentManager cm)
        {
            if (m_saveBtn == null)
            {
                Texture2D texture = cm.Load<Texture2D>("save_btn");
                m_saveBtn = new Button(this, Button.ButtonType.ESaveBtn, texture);
                m_saveBtn.SetPosition(new Rectangle((int)m_boxHandler.m_size.X - texture.Width - 10, 10, texture.Width, texture.Height));

                texture = cm.Load<Texture2D>("play_btn2");
                m_playBtn = new Button(this, Button.ButtonType.EPlayBtn, texture);
                m_playBtn.SetPosition(new Rectangle((int)m_boxHandler.m_size.X - texture.Width - 10, 10, texture.Width, texture.Height));

                texture = cm.Load<Texture2D>("cancel_btn");
                m_cancelBtn = new Button(this, Button.ButtonType.ECancelBtn, texture);
                m_cancelBtn.SetPosition(new Rectangle((int)m_boxHandler.m_size.X - texture.Width - 10, 80, texture.Width, texture.Height));

                texture = cm.Load<Texture2D>("left_btn");
                m_leftBtn = new Button(this, Button.ButtonType.ELeftBtn, texture);
                m_leftBtn.SetPosition(new Rectangle((int)m_boxHandler.m_size.X - texture.Width - 270, 10, texture.Width, texture.Height));

                texture = cm.Load<Texture2D>("right_btn");
                m_rightBtn = new Button(this, Button.ButtonType.ERightBtn, texture);
                m_rightBtn.SetPosition(new Rectangle((int)m_boxHandler.m_size.X - texture.Width - 200, 10, texture.Width, texture.Height));
            }
        }

        public virtual void Clear()
        {
            m_levelData.Clear();
            m_boxHandler.m_catapultPos.X = m_boxHandler.m_catapult.Width;
            m_cameraOffset = 0.0f;
            m_activeLevelItem = null;
        }

        public virtual void ButtonPressed(Button.ButtonType buttonType)
        {
            System.Diagnostics.Debug.WriteLine("LevelHandler "+ buttonType);
            switch (buttonType)
            {
                case Button.ButtonType.ECancelBtn:
                    {
                        System.Windows.MessageBoxResult Choice;
                        Choice = System.Windows.MessageBox.Show("End drawing of the level?", "End drawing", System.Windows.MessageBoxButton.OKCancel);
                        if (Choice == System.Windows.MessageBoxResult.OK)
                        {
                            Clear();
                            GameStateChanged(GameEngine.GameState.EMenuScreenState);
                        }
                        break;
                    }
                case Button.ButtonType.ESaveBtn:
                    {
                        // Check level validity
                        int counter = 0;
                        for (int i = 0; i < m_levelData.Count(); i++)
                        {
                            if (!m_levelData[i].m_placeholder)
                            {
                                m_levelData[i].m_rectangle.X -= (int)m_cameraOffset;
                                counter++;
                            }
                        }
                        if (counter == 0)
                        {
                            System.Windows.MessageBox.Show("Level not ready\nSet some items to the level");
                            return;
                        }

                        System.Windows.MessageBoxResult Choice;
                        Choice = System.Windows.MessageBox.Show("Level ready. Time to save it?", "Save", System.Windows.MessageBoxButton.OKCancel);
                        if (Choice == System.Windows.MessageBoxResult.Cancel)
                            return;

                        // Generate new level name
                        int freeLevelIndex = m_levelStorage.NextFreeLevelIndex();
                        String newlevelName = String.Empty;
                        newlevelName += LevelStorage.LEVELNAME;
                        newlevelName += freeLevelIndex.ToString();
                        System.Diagnostics.Debug.WriteLine("Saved level name is " + newlevelName);
                        // Store level
                        m_levelStorage.StoreLevel(newlevelName, m_levelData);
                        m_levelData.Clear();

                        // Go back to menu
                        m_boxHandler.m_catapultPos.X = m_boxHandler.m_catapult.Width;
                        m_cameraOffset = 0.0f;
                        GameStateChanged(GameEngine.GameState.EMenuScreenState);
                        break;
                    }
                case Button.ButtonType.ELeftBtn:
                    {
                        ChangePositions(-50);
                        break;
                    }
                case Button.ButtonType.ERightBtn:
                    {
                        ChangePositions(50);
                        break;
                    }
            }
        }

        public virtual void CreateLevel()
        {
            m_levelData.Clear();
            m_level = 0;
            CreateLevelEditor();
        }

        public virtual void CreateLevelEditor()
        {
            // Boxes 
            LevelEditorItem item = new LevelEditorItem(true, 
                LevelEditorItem.EditorItemType.EBox1,
                new Rectangle(10, 10, m_boxHandler.m_box1.Width, m_boxHandler.m_box1.Height),
                m_boxHandler.m_box1);
            m_levelData.Add(item);

            item = new LevelEditorItem(true,
                LevelEditorItem.EditorItemType.EBox2p,
                new Rectangle(10, 60, m_boxHandler.m_box2p.Width, m_boxHandler.m_box2p.Height),
                m_boxHandler.m_box2p);
            m_levelData.Add(item);

            item = new LevelEditorItem(true,
                LevelEditorItem.EditorItemType.EBox3p,
                new Rectangle(10, 150, m_boxHandler.m_box3p.Width, m_boxHandler.m_box3p.Height),
                m_boxHandler.m_box3p);
            m_levelData.Add(item);

            item = new LevelEditorItem(true,
                LevelEditorItem.EditorItemType.EBox4p,
                new Rectangle(10, 275, m_boxHandler.m_box4p.Width, m_boxHandler.m_box4p.Height),
                m_boxHandler.m_box4p);
            m_levelData.Add(item);

            item = new LevelEditorItem(true,
                LevelEditorItem.EditorItemType.EBox2l,
                new Rectangle(60, 10, m_boxHandler.m_box2l.Width, m_boxHandler.m_box2l.Height),
                m_boxHandler.m_box2l);
            m_levelData.Add(item);

            item = new LevelEditorItem(true,
                LevelEditorItem.EditorItemType.EBox3l,
                new Rectangle(150, 10, m_boxHandler.m_box3l.Width, m_boxHandler.m_box3l.Height),
                m_boxHandler.m_box3l);
            m_levelData.Add(item);

            item = new LevelEditorItem(true,
                LevelEditorItem.EditorItemType.EBox4l,
                new Rectangle(280, 10, m_boxHandler.m_box4l.Width, m_boxHandler.m_box4l.Height),
                m_boxHandler.m_box4l);
            m_levelData.Add(item);


            // Enemies
            item = new LevelEditorItem(true,
                LevelEditorItem.EditorItemType.EEnemy1,
                new Rectangle(60, 60, m_boxHandler.m_enemy1.Width, m_boxHandler.m_enemy1.Height),
                m_boxHandler.m_enemy1);
            m_levelData.Add(item);

            item = new LevelEditorItem(true,
                LevelEditorItem.EditorItemType.EEnemy2,
                new Rectangle(160, 60, m_boxHandler.m_enemy2.Width, m_boxHandler.m_enemy2.Height),
                m_boxHandler.m_enemy2);
            m_levelData.Add(item);

            item = new LevelEditorItem(true,
                LevelEditorItem.EditorItemType.EEnemy3,
                new Rectangle(260, 60, m_boxHandler.m_enemy3.Width, m_boxHandler.m_enemy3.Height),
                m_boxHandler.m_enemy3);
            m_levelData.Add(item);
        }

        protected virtual LevelEditorItem CreateNewItem(LevelEditorItem tool)
        {
            LevelEditorItem newItem = new LevelEditorItem(false,
                tool.m_type,
                tool.m_rectangle,
                tool.m_texture);

            m_levelData.Add(newItem);
            return newItem;
        }

        public virtual LevelEditorItem isToolLevelItemPressed(TouchLocation tl)
        {
            LevelEditorItem item = null;
            for (int i = 0; i < m_levelData.Count(); i++)
            {
                if (m_levelData[i].m_rectangle.Contains(new Point((int)tl.Position.X, (int)tl.Position.Y)))
                {
                    item = m_levelData[i];
                    //break; // NOTE: take last one
                }
            }

            return item;
        }

        protected virtual void ChangePositions(float cameraOffset)
        {
            m_boxHandler.m_catapultPos.X += (int)cameraOffset;
            
            // Change item position because camera changes
            for (int i = 0; i < m_levelData.Count(); i++)
            {
                LevelEditorItem item = m_levelData[i];
                if (!item.m_placeholder)
                {
                    item.m_rectangle.X += (int)cameraOffset;
                }
            }
            m_cameraOffset += cameraOffset;
            System.Diagnostics.Debug.WriteLine("m_cameraOffset " + m_cameraOffset);
        }


        public virtual void Update(GameTime gameTime, float cameraOffset)
        {
            Vector2 touchPosition;
            TouchCollection touchCollection = TouchPanel.GetState();
            if (touchCollection.Count() > 0)
            {
                TouchLocation tl = touchCollection.First();
                touchPosition = tl.Position;

                if (tl.State == TouchLocationState.Pressed)
                {
                    m_cancelBtn.handleTouch(touchPosition);
                    m_saveBtn.handleTouch(touchPosition);
                    m_leftBtn.handleTouch(touchPosition);
                    m_rightBtn.handleTouch(touchPosition);
                }

                if (tl.State == TouchLocationState.Pressed)
                {
                    // Select new item for the level
                    m_activeLevelItem = isToolLevelItemPressed(tl);

                    // Tool or item?
                    if (m_activeLevelItem != null && m_activeLevelItem.m_placeholder)
                    {
                        // Tool selected, create that kind of new item to the screen
                        m_activeLevelItem = CreateNewItem(m_activeLevelItem);
                    }
                    if (m_activeLevelItem != null)
                    {
                        m_xCap = (int)touchPosition.X - m_activeLevelItem.m_rectangle.X;
                        m_yCap = (int)touchPosition.Y - m_activeLevelItem.m_rectangle.Y;
                    }
                }
                else if (tl.State == TouchLocationState.Moved)
                {
                    // Move item to wanted position
                    if (m_activeLevelItem != null)
                    {
                        Rectangle r = m_activeLevelItem.m_rectangle;
                        if (allowedMove(r, ref m_activeLevelItem))
                        {
                            m_prevPos = r;
                            r.Location = new Point((int)tl.Position.X - m_xCap, (int)tl.Position.Y - m_yCap);
                            m_activeLevelItem.m_rectangle = r;
                        }
                        else
                        {
                            m_activeLevelItem.m_rectangle = m_prevPos;
                            m_activeLevelItem = null;
                        }
                    }
                }
                else if (tl.State == TouchLocationState.Released)
                {
                    // Set item
                    if (m_activeLevelItem != null)
                    {
                        Rectangle r = m_activeLevelItem.m_rectangle;
                        if (allowedMove(r, ref m_activeLevelItem))
                        {
                            r.Location = new Point((int)tl.Position.X - m_xCap, (int)tl.Position.Y - m_yCap);
                            m_activeLevelItem.m_rectangle = r;
                        }
                        else
                        {
                            m_activeLevelItem.m_rectangle = m_prevPos;
                            m_activeLevelItem = null;
                        }
                    }
                }
            }
        }

        protected virtual bool allowedMove(Rectangle r, ref LevelEditorItem skipMe)
        {
            bool ret = true;

            for (int i = 0; i < m_levelData.Count(); i++)
            {
                LevelEditorItem item = m_levelData[i];
                if (!item.m_placeholder && item != skipMe)
                {
                    if (item.m_rectangle.Intersects(r))
                    {
                        ret = false;
                        break;
                    }
                }
            }

            if ((skipMe.m_rectangle.Y + skipMe.m_rectangle.Height) > m_boxHandler.m_groundRec.Y)
            {
                ret = false;
            }
            else if (skipMe.m_rectangle.Y < 0)
            {
                ret = false;
            }
            else if (skipMe.m_rectangle.X < 0)
            {
                ret = false;
            }
            else if ((skipMe.m_rectangle.X + skipMe.m_rectangle.Width) > m_boxHandler.m_size.X)
            {
                ret = false;
            }

            return ret;
        }

        protected virtual void CreateBoxModelFromTextures()
        {
            System.Diagnostics.Debug.WriteLine("m_cameraOffset " + m_cameraOffset);
            // Create Box2D model from created textures
            for (int i = 0; i < m_levelData.Count; i++)
            {
                LevelEditorItem item = m_levelData[i];
                if (!item.m_placeholder)
                {
                    int boxType = 0;
                    bool portrait = true;
                    item.m_rectangle.X -= (int)m_cameraOffset;
                    Vector2 pos = new Vector2(item.m_rectangle.Center.X, item.m_rectangle.Center.Y);

                    // Type of Box2D item
                    if (item.m_type == LevelEditorItem.EditorItemType.EBox1)
                    {
                        boxType = 1;
                        Body newBody = m_boxHandler.CreateBoxBody(boxType, portrait, pos);
                    }
                    else if (item.m_type == LevelEditorItem.EditorItemType.EBox2p)
                    {
                        boxType = 2;
                        Body newBody = m_boxHandler.CreateBoxBody(boxType, portrait, pos);
                    }
                    else if (item.m_type == LevelEditorItem.EditorItemType.EBox3p)
                    {
                        boxType = 3;
                        Body newBody = m_boxHandler.CreateBoxBody(boxType, portrait, pos);
                    }
                    else if (item.m_type == LevelEditorItem.EditorItemType.EBox4p)
                    {
                        boxType = 4;
                        Body newBody = m_boxHandler.CreateBoxBody(boxType, portrait, pos);
                    }
                    else if (item.m_type == LevelEditorItem.EditorItemType.EBox2l)
                    {
                        boxType = 2;
                        portrait = false;
                        Body newBody = m_boxHandler.CreateBoxBody(boxType, portrait, pos);
                    }
                    else if (item.m_type == LevelEditorItem.EditorItemType.EBox3l)
                    {
                        boxType = 3;
                        portrait = false;
                        Body newBody = m_boxHandler.CreateBoxBody(boxType, portrait, pos);
                    }
                    else if (item.m_type == LevelEditorItem.EditorItemType.EBox4l)
                    {
                        boxType = 4;
                        portrait = false;
                        Body newBody = m_boxHandler.CreateBoxBody(boxType, portrait, pos);
                    }
                    else if (item.m_type == LevelEditorItem.EditorItemType.EEnemy1)
                    {
                        Body newBody = m_boxHandler.CreateEnemy(1,pos);
                    }
                    else if (item.m_type == LevelEditorItem.EditorItemType.EEnemy2)
                    {
                        Body newBody = m_boxHandler.CreateEnemy(2, pos);
                    }
                    else if (item.m_type == LevelEditorItem.EditorItemType.EEnemy3)
                    {
                        Body newBody = m_boxHandler.CreateEnemy(3, pos);
                    }
                }
            }
        }


        public virtual void Draw(SpriteBatch spriteBatch, GameTime gameTime)
        {
            // Level editor
            if (m_level == 0 && m_saveBtn != null)
            {
                m_saveBtn.Draw(spriteBatch, gameTime);
                m_cancelBtn.Draw(spriteBatch, gameTime);
                m_leftBtn.Draw(spriteBatch, gameTime);
                m_rightBtn.Draw(spriteBatch, gameTime);

                for (int i = 0; i < m_levelData.Count(); i++)
                {
                    LevelEditorItem item = m_levelData[i];
                    spriteBatch.Draw(item.m_texture, item.m_rectangle, Color.White);
                }
            }

            if (m_activeLevelItem != null)
            {
                spriteBatch.Draw(m_activeLevelItem.m_texture, m_activeLevelItem.m_rectangle, Color.White);
            }
        }
    }
}
